package ch.bfh.fbi.mobicomp.zap06;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import ch.quantasy.android.speech.SpeechService;
import ch.quantasy.android.speech.string.FrenchString;
import ch.quantasy.android.speech.string.GermanString;
import ch.quantasy.android.speech.string.UKString;

/**
 * Zap05 seemed to work until we tried to abort the count down. This is due to
 * the IntentService, where a seperate working thread does take the work from a
 * worker queue. This queue serializes the work so each service-call is executed
 * in sequence.
 * 
 * Zap06 uses a normal Service again, but the needed thread-handling is done 'by
 * hand'. Now the application runs as requested on the emulator. ... Really?
 * 
 * @author reto
 * 
 */
public class Zap06Service extends Service {

	private static final String TAG = "ZAP06";

	private Thread thread;

	public static final String REMOTE_ZAPPER_ACTION = "ch.bfh.fbi.mobicomp.zap06.Zap06Service.REMOTE_ZAPPER_ACTION";
	public static final String ZAPPER_KEY_WORD = "ZAP:";
	private static final String destructionKey = "destroyMe";
	private static final String haltKey = "stopDestroyMe";

	private final Intent speechIntent;
	private long countdown;

	public static Intent getZapperIntent(final String message) {
		Intent intent = null;
		if (message.startsWith(Zap06Service.ZAPPER_KEY_WORD)) {
			intent = new Intent(Zap06Service.REMOTE_ZAPPER_ACTION);
			intent.putExtra("message",
					message.substring(Zap06Service.ZAPPER_KEY_WORD.length()));
		}
		return intent;
	}

	public Zap06Service() {
		this.speechIntent = SpeechService.getSpeechIntent();
	}

	@Override
	public IBinder onBind(final Intent intent) {
		// We do not want to grand explicite access!
		return null;
	}

	@Override
	public int onStartCommand(final Intent intent, final int flags,
			final int startId) {
		Log.d(Zap06Service.TAG, "Service Intent received: " + intent);
		if (intent == null) {
			return super.onStartCommand(intent, flags, startId);
		}
		if (Zap06Service.destructionKey.equals(intent.getExtras().getString(
				"message"))) {
			if (this.thread == null) {
				Log.d(Zap06Service.TAG, "destruction initiated...");
				this.initiateAutoDestruction();
			}
			Log.d(Zap06Service.TAG, "Start");
		} else if (Zap06Service.haltKey.equals(intent.getExtras().getString(
				"message"))) {
			Log.d(Zap06Service.TAG, "destruction aborted...");
			this.resetAutoDestruction();
			Log.d(Zap06Service.TAG, "stop");
		}

		else {
			Log.d(Zap06Service.TAG, "unknown command.");
		}

		return super.onStartCommand(intent, flags, startId);
	}

	private void resetAutoDestruction() {
		if (this.countdown == 0) {
			return;
		}
		try {
			this.thread.interrupt();
			this.thread = null;
			this.countdown = 0;
		} catch (final Exception ex) {
			// if there is no thread.
		}

		SpeechService.setPhrase(this.speechIntent, new UKString(
				"Self destruction sequence aborted."), new GermanString(
				"Selbstzerstörungssequenz abgebrochen."), new FrenchString(
				"Séquence d'autodestruction avortée."));
		this.startService(this.speechIntent);

	}

	private void initiateAutoDestruction() {
		if (this.countdown != 0) {
			return;
		}
		this.countdown = System.currentTimeMillis() + (3 * 60 * 1000);
		SpeechService.setPhrase(this.speechIntent, new UKString(
				"Self destruction sequence initiated."), new GermanString(
				"Selbstzerstörungs Sequenz eingeleitet."), new FrenchString(
				"Séquence d'autodestruction declanchée."));
		this.startService(this.speechIntent);
		this.thread = new Thread() {
			@Override
			public void run() {
				Zap06Service.this.countDown();
			}
		};
		this.thread.start();
	}

	private void countDown() {
		try {
			int timeLeft = (int) ((this.countdown - System.currentTimeMillis()) / 1000);
			while (timeLeft > 70) {
				this.minutesCount(timeLeft);
				Thread.sleep(60000); // 1 Minute
				timeLeft = (int) ((this.countdown - System.currentTimeMillis()) / 1000);
			}
			while (timeLeft > 11) {
				this.secondsBlockCount(timeLeft);
				Thread.sleep(10000); // 10 Seconds
				timeLeft = (int) ((this.countdown - System.currentTimeMillis()) / 1000);
			}
			while (timeLeft > 0) {
				this.secondsCount(timeLeft);
				Thread.sleep(1000); // 1 Second
				timeLeft = (int) ((this.countdown - System.currentTimeMillis()) / 1000);
			}
			this.destroy();
		} catch (final InterruptedException ex) {
		}
	}

	private void minutesCount(final int timeLeft) {
		SpeechService.setPhrase(this.speechIntent, new UKString(""
				+ (1 + (timeLeft / (60))) + "Minutes until self destruction"),
				new GermanString("" + (1 + (timeLeft / (60)))
						+ "Minuten bis zur Selbstzerstörung"),
				new FrenchString("" + (1 + (timeLeft / (60)))
						+ "minutes jusqu'à ce que l'auto-destruction"));
		this.startService(this.speechIntent);
	}

	private void secondsBlockCount(final int timeLeft) {
		if ((timeLeft % 3) == 0) {
			SpeechService.setPhrase(this.speechIntent, new UKString(""
					+ (10 + ((timeLeft / 10) * 10))
					+ "Seconds until self destruction"));
		} else if ((timeLeft % 3) == 1) {
			SpeechService.setPhrase(this.speechIntent, new GermanString(""
					+ (10 + ((timeLeft / 10) * 10))
					+ "Sekunden bis zur Selbstzerstörung"));
		} else {
			SpeechService.setPhrase(this.speechIntent, new FrenchString(""
					+ (10 + ((timeLeft / 10) * 10))
					+ "seconds jusqu'à ce que l'auto-destruction"));
		}
		this.startService(this.speechIntent);
	}

	private void secondsCount(final int timeLeft) {
		SpeechService.setPhrase(this.speechIntent,
				new UKString("" + (timeLeft)));
		this.startService(this.speechIntent);
	}

	private void destroy() {
		this.thread.interrupt();
		this.thread = null;
		this.countdown = 0;
		SpeechService.setPhrase(this.speechIntent, new UKString(
				"Self destroying now."));
		this.startService(this.speechIntent);
	}
}
